package com.leonzx.base.service.system;

import com.leonzx.base.config.init.UserInit;
import com.leonzx.base.dao.system.MenuDAO;
import com.leonzx.base.dao.system.MenuDataDAO;
import com.leonzx.base.dao.system.MenuRoleDAO;
import com.leonzx.base.dao.system.RoleDAO;
import com.leonzx.base.entity.system.Menu;
import com.leonzx.base.entity.system.MenuRole;
import com.leonzx.base.entity.system.Role;
import com.leonzx.base.service.BaseService;
import com.leonzx.base.utils.Constants;
import com.leonzx.base.utils.UUIDUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.util.*;

/**
 * @Author:张勇
 * @Description:
 * @Date: 2018-06-11 15:35
 */
@Service
public class MenuService extends BaseService {
    @Autowired
    private MenuDAO menuDAO;
    @Autowired
    private MenuRoleDAO menuRoleDAO;
    @Autowired
    private RoleDAO roleDAO;
    @Autowired
    private MenuDataDAO menuDataDAO;

    /**
     * 找到所有树并返回组装数据
     *
     * @return
     */
    public List<Map<String, Object>> findAllTree() {
        List<Map<String, Object>> datas = new ArrayList<>();

        Example example = new Example(Menu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("state", Constants.STATE_VAILD);
        example.orderBy("sortNo").asc();

        List<Menu> baseMenus = menuDAO.selectByExample(example);

        for (Menu bm : baseMenus) {
            Map<String, Object> bmm = new HashMap<>();
            //TODO 组装zTree数据
            bmm.put("id", bm.getId());
            bmm.put("name", bm.getName());
            bmm.put("pid", bm.getParentId());
            datas.add(bmm);
        }
        return datas;
    }

    /**
     * 查找所有权限，附加选中状态
     *
     * @param roleId
     * @return
     */
    public List<Map<String, Object>> findAllTreeChecked(String roleId) {
        List<Map<String, Object>> datas = new ArrayList<>();
        //查询所有menu
        Example example = new Example(Menu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("state", Constants.STATE_VAILD);
        example.orderBy("sortNo").asc();
        List<Menu> baseMenus = menuDAO.selectByExample(example);
        for (Menu bm : baseMenus) {
            Map<String, Object> bmm = new HashMap<>();
            bmm.put("id", bm.getId());
            bmm.put("name", bm.getName());
            bmm.put("pid", bm.getParentId());
            datas.add(bmm);
            MenuRole menuRole = new MenuRole();
            menuRole.setRoleId(roleId);
            menuRole.setMenuId(bm.getId());
            Integer menuRoleNo = menuRoleDAO.selectCount(menuRole);
            //查询所有roleId是否关联了menu
            if (menuRoleNo > 0) {
                bmm.put("checked", true);
            }
        }
        return datas;
    }

    /**
     * 查询所有，分配人有，被分配人没有的功能
     *
     * @param userId
     * @return
     */
    public List<Map<String, Object>> findAllTreeHad(String myId, String userId) {
        List<Map<String, Object>> datas = new ArrayList<>();
        List<Menu> menus = menuDAO.selectByUserIdFromUserMenu(myId, userId);
        for (Menu bm : menus) {
            Map<String, Object> bmm = new HashMap<>();
            bmm.put("id", bm.getId());
            bmm.put("name", bm.getName());
            bmm.put("pid", bm.getParentId());
            bmm.put("sortNo", bm.getSortNo());
            if (!datas.contains(bmm)) {
                datas.add(bmm);
            }
            //去重时把会把父菜单排除，下面查询每一个菜单是否有父菜单，加入数据中
            String parentId = bm.getParentId();
            while (StringUtils.isNotBlank(parentId)) {
                Menu menu = menuDAO.selectByPrimaryKey(parentId);
                Map<String, Object> bmm1 = new HashMap<>();
                bmm1.put("id", menu.getId());
                bmm1.put("name", menu.getName());
                bmm1.put("pid", menu.getParentId());
                bmm1.put("sortNo", menu.getSortNo());
                if (!datas.contains(bmm1)) {
                    datas.add(bmm1);
                }
                parentId = menu.getParentId();
            }
        }
        //datas重新排序
        Collections.sort(datas, (o1, o2) -> {
            Integer sortNo1 = (Integer) o1.get("sortNo");
            Integer sortNo2 = (Integer) o2.get("sortNo");
            return sortNo1 - sortNo2;
        });
        return datas;
    }

    /**
     * 根据上级菜单id查询菜单
     *
     * @param id
     * @return
     */
    public List<Menu> findMenuByParentId(String id) {
        Example example = new Example(Menu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("parentId", id);
        criteria.andEqualTo("state", Constants.STATE_VAILD);
        return menuDAO.selectByExample(example);
    }

    /**
     * 根据id跟新数据
     *
     * @param menu
     */
    public void updateMenu(Menu menu) {
        menuDAO.updateByPrimaryKeySelective(menu);
    }

    /**
     * 保存新的菜单
     *
     * @param menu
     */
    public void saveMenu(Menu menu) {
        menu.setCreateTime(new Date());
        menu.setId(UUIDUtils.getUUID());
        menuDAO.insert(menu);
    }

    /**
     * 根据id找上级菜单
     *
     * @param menu
     * @return
     */
    public Menu findParentMenu(Menu menu) {
        String parentId = "";
        if (!Objects.isNull(menuDAO.selectByPrimaryKey(menu))) {
            parentId = menuDAO.selectByPrimaryKey(menu).getParentId();
        }
        Menu menuParent = new Menu();
        if (StringUtils.isNotBlank(parentId)) {
            menuParent.setId(parentId);
            menuParent = menuDAO.selectByPrimaryKey(menuParent);
        }
        return menuParent;
    }

    /**
     * 根据Id找到菜单
     *
     * @param id
     * @return
     */
    public Menu findById(String id) {
        Menu menu = new Menu();
        menu.setId(id);
        return menuDAO.selectByPrimaryKey(menu);
    }

    private List<Menu> getMenuByParentIdAndState(String parentId, Integer state) {
        Example example = new Example(Menu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("parentId", parentId);
        criteria.andEqualTo("state", state);
        criteria.andEqualTo("type", Constants.MENU_MENU);
        example.orderBy("sortNo").asc();
        List<Menu> menus = menuDAO.selectByExample(example);

        if (menus != null && !menus.isEmpty()) {
            for (Menu menu : menus) {
                List<Menu> sonMenus = getMenuByParentIdAndState(menu.getId(), state);
                menu.setSonMenus(sonMenus);
            }
        }
        return menus;
    }

    /**
     * 根据用户ID查询所具有的菜单权限（包括临时权限）
     *
     * @param userId
     * @return
     */
    public List<Menu> getAllByUserId(String userId) {
        //1.查询用户所具有的所有角色
        List<Role> roles = roleDAO.findByUserIdAndState(userId, Constants.STATE_VAILD);
        //2.查询用户有效的临时角色
        List<Role> tempRoles = roleDAO.findTempRoleByUserIdAndState(userId, Constants.STATE_VAILD);
        //3.查询用户有效的临时菜单（权限）
        List<Menu> tempMenus = menuDAO.findTempMenuByUserIdAndState(userId, Constants.STATE_VAILD);
        //4.根据角色查询菜单（权限）
        List<Menu> menus = getMenusByRoles(roles);
        List<Menu> menusTemp = getMenusByRoles(tempRoles);
        //5.菜单权限数据去重
        List<Menu> finalMenus = new ArrayList<>();
        String ids = "";

        for (Menu menu : tempMenus) {
            if (ids.indexOf(menu.getId() + ",") == -1) {
                ids += menu.getId() + ",";
                finalMenus.add(menu);
            }
        }
        for (Menu menu : menus) {
            if (ids.indexOf(menu.getId() + ",") == -1) {
                ids += menu.getId() + ",";
                finalMenus.add(menu);
            }
        }
        for (Menu menu : menusTemp) {
            if (ids.indexOf(menu.getId() + ",") == -1) {
                ids += menu.getId() + ",";
                finalMenus.add(menu);
            }
        }
        return finalMenus;
    }

    /**
     * @param roles
     * @return
     */
    public List<Menu> getMenusByRoles(List<Role> roles) {
        List<Menu> menus = new ArrayList<>();
        for (Role role : roles) {
            List<Menu> ms = menuDAO.findMenuByRoleIdAndState(role.getId(), Constants.STATE_VAILD);
            menus.addAll(ms);
        }
        return menus;
    }

    /**
     * @return
     */
    public List<Menu> getRootMenuByIds(String userId) {
        List<Menu> menus;
        String jsonData = menuDataDAO.findMenuDataByUserId(userId);
        if (StringUtils.isBlank(jsonData)) {
            //取出当前用户所具有的菜单权限
            if (Objects.equals(userId, UserInit.ADMIN)) {
                menus = getAllRootMenuByState(Constants.STATE_VAILD);
                for (Menu menu : menus) {
                    List<Menu> sonMenus = getMenuByParentIdAndState(menu.getId(), Constants.STATE_VAILD);
                    menu.setSonMenus(sonMenus);
                }
                return menus;
            } else {
                menus = getAllByUserId(userId);
            }
            if (menus != null && menus.size() > 0) {
                List<String> menuIds = new ArrayList<>();
                for (Menu menu : menus) {
                    menuIds.add(menu.getId());
                }
                List<Menu> rootMeuns = menuDAO.findRootMenuByIdsAndState(menuIds, Constants.STATE_VAILD);
                for (Menu menu : rootMeuns) {
                    List<Menu> sonMenus = getMenuByParentIdAndIds(menu.getId(), menuIds);
                    menu.setSonMenus(sonMenus);
                }
                return rootMeuns;
            } else {
                return null;
            }
        } else {
            menus = getMenuListByMenuList(jsonData, userId);
            return menus;
        }

    }

    /**
     * 查询所有的顶级菜单
     *
     * @param state
     * @return
     */
    private List<Menu> getAllRootMenuByState(Integer state) {
        Example example = new Example(Menu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("type", Constants.MENU_MENU);
        criteria.andEqualTo("state", state);

        Example.Criteria criteriaOr = example.createCriteria();
        criteriaOr.andEqualTo("parentId", "");
        criteriaOr.orIsNull("parentId");
        example.and(criteriaOr);
        example.orderBy("sortNo").asc();
        return menuDAO.selectByExample(example);
    }

    /**
     * 递归填充子菜单
     *
     * @param id
     * @param menuIds
     * @return
     */
    private List<Menu> getMenuByParentIdAndIds(String id, List<String> menuIds) {
        List<Menu> menus = menuDAO.findMenuByParentIdAndIdsAndState(id, menuIds, Constants.STATE_VAILD);
        if (menus != null && !menus.isEmpty()) {
            for (Menu menu : menus) {
                List<Menu> sonMenus = getMenuByParentIdAndIds(menu.getId(), menuIds);
                menu.setSonMenus(sonMenus);
            }
        }
        return menus;
    }

    /**
     * ztree
     *
     * @Author chen
     * @Date 2018/7/2 14:39
     */
    public List<Map<String, Object>> ztreeGetRootMenuByIds(String userId) {
        List<Map<String, Object>> datas = new ArrayList<>();
        //查询人员个性化菜单
        String menuJson = menuDataDAO.findMenuDataByUserId(userId);
        List<Menu> menus = getUserMenu(userId);
        if (StringUtils.isBlank(menuJson)) {
            //取出当前用户所具有的菜单权限
            if (menus != null && menus.size() > 0) {
                List<String> menuIds = new ArrayList<>();
                for (Menu menu : menus) {
                    menuIds.add(menu.getId());
                }
                List<Menu> rootMeuns = menuDAO.findRootMenuByIdsAndState(menuIds, Constants.STATE_VAILD);

                for (Menu menu : rootMeuns) {
                    datas.add(setMap(menu.getId(), menu.getName(), menu.getParentId(), menu.getUrl(), menu.getIcon()));
                    List<Menu> sonMenus = ztreeGetMenuByParentIdAndIds(menu.getId(), menuIds, datas);
                    for (Menu sonMenu : sonMenus) {
                        datas.add(setMap(sonMenu.getId(), sonMenu.getName(), sonMenu.getParentId(), sonMenu.getUrl(), sonMenu.getIcon()));
                    }
                }
                return datas;
            } else {
                return null;
            }
        } else {
            datas = getMenuListByMenuData(menuJson, menus);
            return datas;
        }
    }

    public Map<String, Object> setMap(String id, String name, String pid, String url, String icon) {
        Map<String, Object> sonMap = new HashMap<>();
        sonMap.put("id", id);
        sonMap.put("name", name);
        sonMap.put("parentId", pid);
        sonMap.put("url", url);
        sonMap.put("micon", icon);
        return sonMap;
    }

    private List<Menu> ztreeGetMenuByParentIdAndIds(String id, List<String> menuIds, List<Map<String, Object>> datas) {
        List<Menu> menus = menuDAO.findMenuByParentIdAndIdsAndState(id, menuIds, Constants.STATE_VAILD);
        if (menus != null && !menus.isEmpty()) {
            for (Menu menu : menus) {
                List<Menu> sonMenus = ztreeGetMenuByParentIdAndIds(menu.getId(), menuIds, datas);
                for (Menu sonMenu : sonMenus) {
                    datas.add(setMap(sonMenu.getId(), sonMenu.getName(), sonMenu.getParentId(), sonMenu.getUrl(), sonMenu.getIcon()));
                }
            }
        }
        return menus;
    }

    /**
     * 返回map
     *
     * @Author chen
     * @Date 2018/7/2 17:04
     */
    public List<Map<String, Object>> getMenuListByMenuData(String jsonData, List<Menu> ms) {
        List<Map<String, Object>> datas = new ArrayList<>();
        if (StringUtils.isNotBlank(jsonData)) {
            List<Object> jsonObjects = gson.fromJson(jsonData, ArrayList.class);
            List<Menu> menus = new ArrayList<>();
            List<Menu> parentMenus = new ArrayList<>();
            for (Object jo : jsonObjects) {
                Menu m = gson.fromJson(gson.toJson(jo), Menu.class);
                if (StringUtils.isBlank(m.getParentId())) {
                    parentMenus.add(m);
                }
                menus.add(gson.fromJson(gson.toJson(jo), Menu.class));
            }
            for (int i = 0; i < parentMenus.size(); i++) {
                Menu parentMenu = parentMenus.get(i);
                datas.add(setMap(parentMenu.getId(), parentMenu.getName(), parentMenu.getParentId(), parentMenu.getUrl(), parentMenu.getIcon()));
                List<Menu> sonMenus = getSonMenus(parentMenu.getId(), menus, datas);
                for (int j = 0; j < sonMenus.size(); j++) {
                    datas.add(setMap(sonMenus.get(j).getId(), sonMenus.get(j).getName(), sonMenus.get(j).getParentId(), sonMenus.get(j).getUrl(), sonMenus.get(j).getIcon()));
                }
            }
        }
        datas = getCustomMenuAndNewMenu(datas, ms);
        return datas;
    }

    public List<Menu> getSonMenus(String parentId, List<Menu> menus, List<Map<String, Object>> datas) {
        List<Menu> sonMenus = new ArrayList<>();
        if (menus != null && menus.size() > 0) {
            for (int i = 0; i < menus.size(); i++) {
                Menu sonMenu = menus.get(i);
                if (parentId.equals(sonMenu.getParentId())) {
                    sonMenus.add(sonMenu);
                }
            }
            if (sonMenus != null && sonMenus.size() > 0) {
                for (int i = 0; i < sonMenus.size(); i++) {
                    List<Menu> s = getSonMenus(sonMenus.get(i).getId(), menus, datas);
                    for (int j = 0; j < s.size(); j++) {
                        datas.add(setMap(s.get(j).getId(), s.get(j).getName(), s.get(j).getParentId(), s.get(j).getUrl(), s.get(j).getIcon()));
                    }
                }
            }
        }
        return sonMenus;
    }

    /**
     * 返回list
     *
     * @Author chen
     * @Date 2018/7/2 17:04
     */
    public List<Menu> getMenuListByMenuList(String jsonData, String userId) {
        List<Menu> parentMenus = new ArrayList<>();
        if (StringUtils.isNotBlank(jsonData)) {
            List<Menu> ms = getUserMenu(userId);
            List<Object> jsonObjects = gson.fromJson(jsonData, ArrayList.class);
            List<Menu> menus = new ArrayList<>();
            for (Object jo : jsonObjects) {
                menus.add(gson.fromJson(gson.toJson(jo), Menu.class));
            }
            List<Menu> allMenu = getCustomMenuAndNewMenuIndex(menus, ms);
            for (Menu m : allMenu) {
                if (StringUtils.isBlank(m.getParentId())) {
                    parentMenus.add(m);
                }
            }
            for (int i = 0; i < parentMenus.size(); i++) {
                Menu parentMenu = parentMenus.get(i);
                List<Menu> sonMenus = getSonMenuList(parentMenu.getId(), allMenu, parentMenus);
                parentMenu.setSonMenus(sonMenus);
            }
        }
        return parentMenus;
    }

    public List<Menu> getSonMenuList(String parentId, List<Menu> menus, List<Menu> finalMenus) {
        List<Menu> sonMenus = new ArrayList<>();
        if (menus != null && menus.size() > 0) {
            for (int i = 0; i < menus.size(); i++) {
                Menu sonMenu = menus.get(i);
                if (parentId.equals(sonMenu.getParentId())) {
                    sonMenus.add(sonMenu);
                }
            }
            if (sonMenus != null && sonMenus.size() > 0) {
                for (int i = 0; i < sonMenus.size(); i++) {
                    Menu sonMenu = sonMenus.get(i);
                    List<Menu> s = getSonMenuList(sonMenus.get(i).getId(), menus, finalMenus);
                    sonMenu.setSonMenus(s);
                }
            }
        }
        return sonMenus;
    }

    /**
     * 得到所有的权限菜单
     *
     * @return
     */
    public List<Menu> getAll() {
        Example example = new Example(Menu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("state", Constants.STATE_VAILD);
        example.orderBy("sortNo").asc();
        List<Menu> menus = menuDAO.selectByExample(example);
        return menus;
    }

    /**
     * 返回个性化菜单和该人员所有的个性化菜单之外菜单的集合
     *
     * @Author chen
     * @Date 2018/7/3 11:08
     */
    public List<Map<String, Object>> getCustomMenuAndNewMenu(List<Map<String, Object>> datas, List<Menu> ms) {
        if (datas != null && datas.size() > 0) {
            String menuIds = "";
            for (Map<String, Object> data : datas) {
                if (menuIds.indexOf(data.get("id").toString()) == -1) {
                    menuIds += data.get("id") + ",";
                }
            }
            menuIds = menuIds.substring(0, menuIds.length() - 1);
            if (ms != null && ms.size() > 0) {
                for (Menu menu : ms) {
                    if (menuIds.indexOf(menu.getId()) == -1) {
                        datas.add(setMap(menu.getId(), menu.getName(), menu.getParentId(), menu.getUrl(), menu.getIcon()));
                    }
                }
            }
        }
        return datas;
    }

    /**
     * 返回个性化菜单和该人员所有的个性化菜单之外菜单的集合
     *
     * @Author chen
     * @Date 2018/7/3 11:30
     */
    public List<Menu> getCustomMenuAndNewMenuIndex(List<Menu> customMenus, List<Menu> newMenus) {
        if (customMenus != null && customMenus.size() > 0) {
            String customMenuIds = "";
            for (Menu menu : customMenus) {
                if (customMenuIds.indexOf(menu.getId()) == -1) {
                    customMenuIds += menu.getId() + ",";
                }
            }
            customMenuIds = customMenuIds.substring(0, customMenuIds.length() - 1);
            if (newMenus != null && newMenus.size() > 0) {
                for (Menu menu : newMenus) {
                    if (customMenuIds.indexOf(menu.getId()) == -1) {
                        customMenus.add(menu);
                    }
                }
            }
        }
        return customMenus;
    }

    public List<Menu> getUserMenu(String userId) {
        List<Menu> menus = new ArrayList<>();
        if (Objects.equals(userId, UserInit.ADMIN)) {
            Example example = new Example(Menu.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("type", Constants.MENU_MENU);
            criteria.andEqualTo("state", Constants.STATE_VAILD);
            Example.Criteria criteriaOr = example.createCriteria();
            example.and(criteriaOr);
            example.orderBy("sortNo").asc();
            return menuDAO.selectByExample(example);
        } else {
            menus = getAllByUserId(userId);
        }
        return menus;
    }
}
